
#include "mainwindow.h"
#include "analyzers/logcatmainwindow.h"
#include "dialog/genfiltervaluesdialog.h"
#include "ui_mainwindow.h"

#include <QDropEvent>
#include <QFileDialog>
#include <QFileSystemModel>
#include <QMessageBox>
#include <QMimeData>
#include <QMimeDatabase>
#include <QTextStream>
#include <QTimer>

#include <widgets/lgfilteritem.h>

#include <dialog/dictionarydialog.h>

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
  , ui(new Ui::MainWindow)
  , model(new QFileSystemModel)
{
    ui->setupUi(this);
    ui->lg_log_file_treeview->setModel(model);

    for (int i = 1; i < model->columnCount(); ++i)
        ui->lg_log_file_treeview->hideColumn(i);

    ui->lg_log_editor->setWordWrapMode(QTextOption::WrapMode::NoWrap);
    connect(ui->cb_reverse, &QCheckBox::stateChanged, this, &MainWindow::slotStateChanged);
    connect(ui->lg_cb_pick_start, &QCheckBox::stateChanged, this, &MainWindow::slotStateChanged);
}
MainWindow::~MainWindow()
{
	
}

void MainWindow::append_filter_item(QString text, int index)
{
    QStringList values =  lg_list_values();
    if (values.contains(text)) {
        auto item = find_filter_item(text);
        if (item) {
            auto itemWidget = (LGFilterItem*) ui->lg_filter_list->itemWidget(item);
            itemWidget->increment();
        }
        return; // 跳过重复项
    }

    auto item = new QListWidgetItem;
    auto itemWidget = LGFilterItem::newFilterItem(true, text);
    itemWidget->setIndex(index);

    ui->lg_filter_list->addItem(item);
    ui->lg_filter_list->setItemWidget(item, itemWidget);

    connect(itemWidget, &LGFilterItem::onStateChanged, this, &MainWindow::slotStateChanged);
}

QListWidgetItem *MainWindow::find_filter_item(QString text)
{
    int count = ui->lg_filter_list->count();
    for (int i = 0; i < count; ++i) {
        auto item = ui->lg_filter_list->item(i);
        auto itemWidget = (LGFilterItem*) ui->lg_filter_list->itemWidget(item);
        if (itemWidget->text() == text) {
            return item;
        }
    }
    return nullptr;
}

void MainWindow::on_lg_filter_add_clicked()
{
    QString log = ui->lg_log_editor->toPlainText();
    QString text = ui->lg_log_editor->textCursor().selectedText();

    int text_jump = text.length();

    int start = -1;
    while ((start = log.indexOf(text, start+13)) != -1) {
        append_filter_item(text);
        // start += text_jump;
    }

    updateLog();
}

void MainWindow::remove_filter_item(QListWidgetItem *item)
{
    // 前置条件判断
    if (!item) {
        item = ui->lg_filter_list->currentItem();
    }

    if (item) {
        ui->lg_filter_list->takeItem(ui->lg_filter_list->currentRow());
        ui->lg_filter_list->removeItemWidget(item);
        delete item;
    }
}

void MainWindow::on_lg_filter_del_clicked()
{
    auto item = ui->lg_filter_list->currentItem();
    if (item) {
        remove_filter_item(item);
    }
    updateLog();
}

void MainWindow::on_lg_filter_create_clicked()
{
    QString text = ui->lg_filter_create_edit->text();
    append_filter_item(text);
    ui->lg_filter_create_edit->clear();
    updateLog();
}

void MainWindow::on_lg_log_paste_textChanged(const QString &arg1)
{
    setLog(arg1);
    updateLog();
}

QStringList MainWindow::lg_list_values()
{
    QStringList values;
    int count = ui->lg_filter_list->count();
    for (int i = 0; i < count; ++i) {
        auto item = ui->lg_filter_list->item(i);
        auto itemWidget = (LGFilterItem*) ui->lg_filter_list->itemWidget(item);
        if (itemWidget->isChecked()) {
            values << itemWidget->text();
        }
    }
    return values;
}

QList<ItemKV> MainWindow::lg_filter_list_kv()
{
    QList<ItemKV> kvs;
    int count = ui->lg_filter_list->count();
    for (int i = 0; i < count; ++i) {
        auto item = ui->lg_filter_list->item(i);
        auto itemWidget = (LGFilterItem*) ui->lg_filter_list->itemWidget(item);
        if (itemWidget->isChecked()) {
            kvs.append(ItemKV{itemWidget->text(), itemWidget->index(), itemWidget->isBlocked()});
        }
    }
    return kvs;
}

void MainWindow::updateLog(bool is_timer_call, int interval)
{
    static QTimer timer;
    timer.disconnect();
    QObject::connect(&timer, &QTimer::timeout, [=]() {
        timer.stop();
        updateLog(true);
    });
    // seep interval's, call updateLog with Timer
    if (!is_timer_call) {
        timer.start(interval);
        return;
    }

    QList<ItemKV> kvs = lg_filter_list_kv();
    auto lines = m_log.split("\n");
    QStringList logs;

    // 1. 从{此}开始
    if (!ui->lg_pick_start->text().isEmpty()) {
        QString start = ui->lg_pick_start->text();

        // {反向}行动
        if (ui->lg_cb_pick_start->isChecked()) {
            QStringList lastLogs;
            while (lines.count()) {
                lastLogs.prepend(lines.last());
                if (lines.last().contains(start, Qt::CaseInsensitive)) {
                    break;
                }
                lines.removeLast();
            }
            lines = lastLogs;
        } else
            // 原始
            while (lines.count()) {
                if (lines.first().contains(start, Qt::CaseInsensitive)) {
                    break;
                }
                lines.removeFirst();
            }
    }

    // 2. 到{此}结束
    if (!ui->lg_pick_stop->text().isEmpty()) {
        QString stop = ui->lg_pick_stop->text();
        while (lines.count()) {
            if (lines.last().contains(stop, Qt::CaseInsensitive)) {
                break;
            }
            lines.removeLast();
        }
    }


    // 3. 挑选待显示的 logs 行
    foreach (auto line, lines) {
        // kvs 过滤表不为空时进入筛选操作
        if (kvs.count() != 0) {
            // line 行是否保命中
            bool exists = false;
            // line 行是否被 block 掉了
            bool blocked = false;

            // 1. 当前 line 行，测试命中 kvs 筛选项，预筛选条件
            foreach (auto kv, kvs) {
                // line 行包含 kv.text 时
                if (line.contains(kv.text)) {
                    // 命中时立即完成额外参数
                    if (kv.blocked)
                        blocked = kv.blocked;
                }
            }

            // 2. 当前 line 行，测试命中 kvs 筛选项
            foreach (auto kv, kvs) {
                // line 行包含 kv.text 时
                if (line.contains(kv.text)) {
                    // index 为 0 的 kv 是手动生成的
                    if (kv.index == 0) { /// fixme: 这里在选中非分割项时，直接跳过 index 为 0的精度检查
                        exists = true;
                        break;
                    }
                    //
                    if (line.split(QRegExp("\\s+")).length() > kv.index && kv.text.startsWith(line.split(QRegExp("\\s+")).at(kv.index))) {
                        exists = true;
                        break;
                    }
                }
            }

            // 命中过滤，并且反向要求时
            if (exists && ui->cb_reverse->isChecked()) {
                // 被命中项的 blocked 条目的条件
                if (!blocked)
                    logs.append(line);
            // 未命中过滤，并且不反向要求时
            } else if (!exists && !ui->cb_reverse->isChecked()) {
                logs.append(line);
            }
        } else {
            logs.append(line);
        }
    }

    // use dictionary
    if (ui->lg_comb_dictionary->currentIndex() != 0) {
        auto dicts = DictionaryDialog().getDictionary();
        for (int i = 0; i < logs.length(); ++i) {
            for (int j = 0; j < dicts.length(); ++j) {
                if (dicts[j].enabled)
                    logs[i].replace(dicts[j].original, dicts[j].meaning);
            }
        }
    }

    ui->lg_log_editor->setText(logs.join("\n"));
}

void MainWindow::slotStateChanged()
{
    updateLog();
}

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    // 接受拖放事件
    if (event->mimeData()->hasUrls()) {
        event->acceptProposedAction();
    }
}

void MainWindow::open_log_file(QString filePath)
{
    QFile file(filePath);
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        // 读取文件内容并设置到 UI 中
        // 为了处理 virtual file 或 tmpfs 中的，不使用 readAll
        QTextStream in(&file);
        setLog(in.readAll());
        file.close();
        updateLog();
    } else {
        // 文件打开失败，提示用户
        QMessageBox::warning(this, "错误", "无法打开文件: " + filePath);
    }
}

void MainWindow::dropEvent(QDropEvent *event)
{
    // 检查是否有文件被拖入
    if (event->mimeData()->hasUrls()) {
        QUrl fileUrl = event->mimeData()->urls().first(); // 只处理第一个文件
        if (fileUrl.isLocalFile()) {
            QString filePath = fileUrl.toLocalFile(); // 获取文件路径
            QMimeDatabase mdb;
            QMimeType mimeType = mdb.mimeTypeForFile(filePath); // 获取文件类型

            bool shouldOpen = false;
            // 检查文件类型是否为文本文件
            if (mimeType.name() == "text/plain" || mimeType.name() == "text/x-log") {
                shouldOpen = true;
            } else {
                // 如果文件类型不是文本文件，弹出提示框询问用户
                QMessageBox::StandardButton reply = QMessageBox::question(
                    this,
                    "确定打开此文件?",
                    "该文件类型为: " + mimeType.name() + "\n是否继续打开?",
                    QMessageBox::Yes | QMessageBox::No
                );
                shouldOpen = (reply == QMessageBox::Yes);
            }

            // 如果用户确认打开文件
            if (shouldOpen) {
                // 检查是否为目录
                if (mimeType.name() == "inode/directory") {
                    model->setRootPath(filePath);
                    ui->lg_log_file_treeview->setRootIndex(model->index(filePath));
                    return;
                }

                open_log_file(filePath);
            }
        }
    }
}

QString MainWindow::log() const
{
    return m_log;
}

void MainWindow::setLog(const QString &newLog)
{
    m_log = newLog;
}

void MainWindow::on_lg_log_editor_slider_actionTriggered(int action)
{

}

void MainWindow::on_lg_log_editor_slider_valueChanged(int value)
{
    auto font = ui->lg_log_editor->font();
    font.setPointSize(value);
    ui->lg_log_editor->setFont(font);
}


void MainWindow::on_lg_log_editor_wordwrap_stateChanged(int arg1)
{
    ui->lg_log_editor->setWordWrapMode((arg1 == Qt::CheckState::Checked) ? QTextOption::WrapMode::WordWrap : QTextOption::WrapMode::NoWrap);
}


void MainWindow::on_action_filter_gen_values_triggered()
{
    GenFilterValuesDialog dialog;
    if (dialog.exec() == QDialog::Accepted) {
        auto values = dialog.values(m_log);
        foreach (auto var, values) {
            append_filter_item(var, dialog.index());
        }
        updateLog();
    }
}


void MainWindow::on_lg_filter_clean_clicked()
{
    while(ui->lg_filter_list->count() != 0) {
        ui->lg_filter_list->setCurrentRow(0);
        remove_filter_item();
    }
    updateLog();
}

void MainWindow::on_lg_log_file_treeview_entered(const QModelIndex &index)
{

}

void MainWindow::on_lg_log_file_treeview_clicked(const QModelIndex &index)
{
    ui->statusbar->showMessage(model->filePath(index));
    if (model->isDir(index) == false) {
        open_log_file(model->filePath(index));
    }
}


void MainWindow::on_lg_filter_search_textChanged(const QString &arg1)
{
    // 1. arg1 为空时，拿到所有 itemWidget 都显示
    int count = ui->lg_filter_list->count();
    for (int i = 0; i < count; ++i) {
        auto item = ui->lg_filter_list->item(i);
        auto itemWidget = (LGFilterItem*) ui->lg_filter_list->itemWidget(item);
        item->setHidden(false);
    }

    //
    for (int i = 0; i < count; ++i) {
        auto item = ui->lg_filter_list->item(i);
        auto itemWidget = (LGFilterItem*) ui->lg_filter_list->itemWidget(item);
        if (itemWidget->text().contains(arg1, Qt::CaseInsensitive)) {
            item->setHidden(false);
        } else {
            item->setHidden(true);
        }
    }
}


void MainWindow::on_action_open_android_analyzer_triggered()
{
    LogcatMainWindow *window = new LogcatMainWindow;
    window->setLogcat(m_log);
    window->setPickRange(ui->lg_pick_start->text(), ui->lg_pick_stop->text());
    window->show();
}


void MainWindow::on_lg_pick_start_textChanged(const QString &arg1)
{
    updateLog();
}

void MainWindow::on_lg_pick_stop_textChanged(const QString &arg1)
{
    updateLog();
}


void MainWindow::on_lg_btn_open_clicked()
{
//    QString defpath = "/run/user/1000/gvfs/sftp:host=192.168.1.130,user=zinface/media/zinface/1675ea15-00f0-47e9-9eaf-5eb050f9e78a/android14/android-14.0.0_r1/system-logs";
    QString defpath = "/media/zinface/2T/android-14/android-14.0.0_r1/system-logs";
    QString dirpath = QFileDialog::getExistingDirectory(this, "打开目录", defpath);
    if (!dirpath.isEmpty()) {
        model->setRootPath(dirpath);
        ui->lg_log_file_treeview->setRootIndex(model->index(dirpath));
    }
}


void MainWindow::on_lg_log_editor_selectionChanged()
{
    static QTimer timer;
    timer.disconnect();

    QObject::connect(&timer, &QTimer::timeout, [=]() {
        timer.stop();

        QString text = ui->lg_log_editor->textCursor().selectedText();
        QStringList lines = ui->lg_log_editor->toPlainText().split("\n");
        int likes = 0;
        foreach (auto &line, lines) {
            if (line.contains(text)) {
                likes++;
            }
        }
        ui->statusbar->showMessage(QString("相同选中内容有: %1 项").arg(likes));
    });

    // seep 1s, call updateLog
    timer.start(1000);
}


void MainWindow::on_lg_comb_dictionary_currentTextChanged(const QString &arg1)
{
    updateLog();
}


void MainWindow::on_action_open_dictionary_triggered()
{
    DictionaryDialog dialog;
    dialog.exec();
    updateLog();
}

